(function () {
    // 全局只有一个事件池
    let pond = {};

    // 向事件池中订阅方法
    const on = function on(type, func) {
        if (!pond.hasOwnProperty(type)) pond[type] = [];
        let arr = pond[type];
        if (arr.includes(func)) return; //去重
        arr.push(func);
    };

    // 从事件池中移除订阅
    const off = function off(type, func) {
        let arr = pond[type] || [];
        if (arr.length === 0) return;
        let i = 0,
            item;
        for (; i < arr.length; i++) {
            item = arr[i];
            if (item === func) {
                // arr.splice(i, 1); //引发数组塌陷
                arr[i] = null;
                return;
            }
        }
    };

    // 通知事件池中,指定类型的方法去执行
    const fire = function fire(type, ...params) {
        let arr = pond[type] || [],
            i = 0,
            item;
        for (; i < arr.length; i++) {
            item = arr[i];
            if (typeof item === 'function') {
                item(...params);
                continue;
            }
            // 当期这一项不是函数，则我们把其移除掉
            arr.splice(i, 1);
            i--;
        }
    };

    /* 暴露API */
    let sub = {
        on,
        off,
        fire
    };
    if (typeof window !== 'undefined') window.sub = sub;
    if (typeof module === 'object' && typeof module.exports === 'object') module.exports = sub;
})();